package com.freestyle.jms.common;

import com.freestyle.jmssample.api.JMSDeclare;
import com.rabbitmq.client.AMQP;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Map;

/**
 * JMS定义类的RabbitMQ实例，有交换机管理，队列管理
 * Created by rocklee on 2022/1/6 14:23
 */
@Component
@Slf4j
public class RabbitMQDeclare implements JMSDeclare {

  @Resource
  private RabbitAdmin rabbitAdmin;

  @Override
  public DirectExchange newDirectExchange(String exChange){
    return (DirectExchange) initExchange(exChange,ExchangeTypes.DIRECT,true,false,null);
  }
  @Override
  public TopicExchange newTopicExchange(String exChange){
    return (TopicExchange) initExchange(exChange,ExchangeTypes.TOPIC,true,false,null);
  }
  @Override
  public FanoutExchange newFanoutExchange(String exChange){
    return (FanoutExchange) initExchange(exChange,ExchangeTypes.FANOUT,true,false,null);
  }
  @Override
  public HeadersExchange newHeadersExchange(String exChange){
    return (HeadersExchange) initExchange(exChange,ExchangeTypes.HEADERS,true,false,null);
  }

  /***
   * 初始化新建交换机
   * @param exChange 交换机名称
   * @param exchangeType ， 参考ExchangeTypes
   * @param isDurable 是否持久化，重启mq也存在
   * @param isAutoDelete 是否自动删除，自动删除的前提是没有有一个队列与之绑定
   * @param arguments 额外参数
   * @return 返回交换机实例
   */
  @Override
  public Exchange initExchange(String exChange, String exchangeType, boolean isDurable, boolean isAutoDelete, Map<String, Object> arguments) {
    switch (exchangeType) {
      case ExchangeTypes.DIRECT:
        return new DirectExchange(exChange, isDurable, isAutoDelete, arguments);
      case ExchangeTypes.TOPIC:
        return new TopicExchange(exChange, isDurable, isAutoDelete, arguments);
      case ExchangeTypes.FANOUT:
        return new FanoutExchange(exChange, isDurable, isAutoDelete,arguments);
      case ExchangeTypes.HEADERS:
        return new HeadersExchange(exChange, isDurable, isAutoDelete,arguments);
      default:
        return null;
    }
  }

  @Override
  public Exchange declareExchange(Exchange exChange){
      log.info("declareExchange:"+exChange.getName());
      rabbitAdmin.declareExchange(exChange);
      log.info("declare exchange successfully");
      return exChange;
  }
  @Override
  public boolean deleteExchange(String exChange){
    return rabbitAdmin.deleteExchange(exChange);
  }

  /**
   * 判断交换机是否存在
   * @param exChange 交换机名称
   * @return 返回true/false
   */
  @Override
  public boolean isExChangeExists(String exChange){
    if (!StringUtils.hasText(exChange))
      throw new IllegalArgumentException("Invalid exChange name");
    String ret=rabbitAdmin.getRabbitTemplate().execute(c->{
      try {
        c.exchangeDeclarePassive(exChange);
        return "OK";
      }
      catch (Exception e){
        return null;
      }
    });
    return ret!=null;
  }

  /***
   * 初始化新建队列
   * @param queue 队列名称
   * @param isDurable 是否持久化，mq重启也不丢失其数据
   * @param isExclusive 是否排他，如果是排他，则该队列对首次声明他的连接有效，并在连接断开时自动删除
   * @param isAutoDelete 是否自动删除
   * @param arguments 额外参数
   * @return 返回队列实例
   */
  @Override
  public Queue initQueue(String queue, boolean isDurable, boolean isExclusive, boolean isAutoDelete, Map<String, Object> arguments){
    Queue q=new Queue(queue,isDurable,isExclusive,isAutoDelete,arguments);
    rabbitAdmin.declareQueue(q);
    log.info("declare queue {} successfully",queue);
    return q;
  }
  @Override
  public Queue initQueue(String queue, boolean... isDurable){
    return initQueue(queue,isDurable.length==0||isDurable[0]?true:false,false,false,null);
  }
  @Override
  public boolean deleteQueue(String queue){
    return rabbitAdmin.deleteQueue(queue);
  }
  /***
   * 判断队列是否存在
   * @param queue 队列名称
   * @return 返回true/false
   */
  @Override
  public boolean isQueueExists(String queue){
    if (!StringUtils.hasText(queue))
      throw new IllegalArgumentException("Invalid queue name");
    String ret=rabbitAdmin.getRabbitTemplate().execute(c->{
      try {
        AMQP.Queue.DeclareOk declareOk = c.queueDeclarePassive(queue);
        return declareOk.getQueue();
      }
      catch (Exception e){
        return null;
      }
    });
    return ret!=null;
  }

  /***
   * 清除队列中的消息
   * @param queue 队列名称
   * @return 返回消息数量
   */
  @Override
  public int clearQueueData(String queue){
    return rabbitAdmin.purgeQueue(queue);
  }

  /***
   * 将队列与交换机、路由绑定
   * @param queue 队列名称
   * @param exChange 交换机名称
   * @param routKey 路由名称
   * @param arguments 额外参数
   */
  public void bindQueue(String queue, String exChange, String routKey,@Nullable Map<String, Object> arguments){
    Binding binding=new Binding(queue, Binding.DestinationType.QUEUE,exChange,routKey,arguments);
    rabbitAdmin.declareBinding(binding);
  }

  public RabbitAdmin getRabbitAdmin() {
    return rabbitAdmin;
  }
}
